package cn.com.franke.basic;

import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Ordering;
import com.google.common.primitives.Ints;
import com.sun.istack.internal.Nullable;
import org.apache.commons.lang3.builder.ReflectionToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.junit.Test;

import java.util.*;

/**
 * Created by liuxianzhao on 2017/4/26.
 */
public class OrderingTest {


    @Test
    public void test1() {
        Ordering<String> byLengthOrdering = new Ordering<String>() {
            public int compare(String left, String right) {
                return Ints.compare(left.length(), right.length());
            }
        };
        List<String> list = new ArrayList<>();
        list.add("liu");
        list.add("xian");
        list.add("zhao");
        list.add("java");
        list.add("engineer");
        System.out.println(list.toString());

        System.out.println(byLengthOrdering.sortedCopy(list));

        List<String> list1 = Lists.newArrayList();
        list1.add("peida");
        list1.add("jerry");
        list1.add("harry");
        list1.add("eva");
        list1.add("jhon");
        list1.add("neron");

        System.out.println("list1:" + list1);
        /*
        natural()：使用Comparable类型的自然顺序， 例如：整数从小到大，字符串是按字典顺序;
　　usingToString() ：使用toString()返回的字符串按字典顺序进行排序；
　　arbitrary() ：返回一个所有对象的任意顺序， 即compare(a, b) == 0 就是 a == b (identity equality)。 本身的排序是没有任何含义， 但是在VM的生命周期是一个常量。
         */
        Ordering<String> naturalOrdering = Ordering.natural();
        Ordering<Object> usingToStringOrdering = Ordering.usingToString();
        Ordering<Object> arbitraryOrdering = Ordering.arbitrary();

        System.out.println("naturalOrdering:" + naturalOrdering.sortedCopy(list1));
        System.out.println("usingToStringOrdering:" + usingToStringOrdering.sortedCopy(list1));
        System.out.println("arbitraryOrdering:" + arbitraryOrdering.sortedCopy(list1));
    }

    /**
     * reverse(): 返回与当前Ordering相反的排序:
     * 　　nullsFirst(): 返回一个将null放在non-null元素之前的Ordering，其他的和原始的Ordering一样；
     * 　　nullsLast()：返回一个将null放在non-null元素之后的Ordering，其他的和原始的Ordering一样；
     * 　　compound(Comparator)：返回一个使用Comparator的Ordering，Comparator作为第二排序元素，例如对bug列表进行排序，先根据bug的级别，再根据优先级进行排序；
     * 　　lexicographical()：返回一个按照字典元素迭代的Ordering；
     * 　　onResultOf(Function)：将function应用在各个元素上之后, 在使用原始ordering进行排序；
     * 　　greatestOf(Iterable iterable, int k)：返回指定的第k个可迭代的最大的元素，按照这个从最大到最小的顺序。是不稳定的。
     * 　　leastOf(Iterable<E> iterable,int k)：返回指定的第k个可迭代的最小的元素，按照这个从最小到最大的顺序。是不稳定的。
     * 　　isOrdered(Iterable)：是否有序，Iterable不能少于2个元素。
     * 　　isStrictlyOrdered(Iterable)：是否严格有序。请注意，Iterable不能少于两个元素。
     * 　　sortedCopy(Iterable)：返回指定的元素作为一个列表的排序副本。
     */
    @Test
    public void testOrdering() {
        List<String> list = Lists.newArrayList();
        list.add("peida");
        list.add("jerry");
        list.add("harry");
        list.add("eva");
        list.add("jhon");
        list.add("neron");

        System.out.println("list:" + list);

        Ordering<String> naturalOrdering = Ordering.natural();
        System.out.println("naturalOrdering:" + naturalOrdering.sortedCopy(list));

        List<Integer> listReduce = Lists.newArrayList();
        for (int i = 9; i > 0; i--) {
            listReduce.add(i);
        }

        List<Integer> listtest = Lists.newArrayList();
        listtest.add(1);
        listtest.add(3);
        listtest.add(1);
        listtest.add(2);


        Ordering<Integer> naturalIntReduceOrdering = Ordering.natural();

        System.out.println("listtest:" + listtest);
        System.out.println(naturalIntReduceOrdering.isOrdered(listtest));
        System.out.println(naturalIntReduceOrdering.isStrictlyOrdered(listtest));


        System.out.println("naturalIntReduceOrdering:" + naturalIntReduceOrdering.sortedCopy(listReduce));
        System.out.println("listReduce:" + listReduce);


        System.out.println(naturalIntReduceOrdering.isOrdered(naturalIntReduceOrdering.sortedCopy(listReduce)));
        System.out.println(naturalIntReduceOrdering.isStrictlyOrdered(naturalIntReduceOrdering.sortedCopy(listReduce)));


        Ordering<String> natural = Ordering.natural();

        List<String> abc = ImmutableList.of("a", "b", "c");
        System.out.println(natural.isOrdered(abc));
        System.out.println(natural.isStrictlyOrdered(abc));

        System.out.println("isOrdered reverse :" + natural.reverse().isOrdered(abc));

        List<String> cba = ImmutableList.of("c", "b", "a");
        System.out.println(natural.isOrdered(cba));
        System.out.println(natural.isStrictlyOrdered(cba));
        System.out.println(cba = natural.sortedCopy(cba));

        System.out.println("max:" + natural.max(cba));
        System.out.println("min:" + natural.min(cba));

        System.out.println("leastOf:" + natural.leastOf(cba, 2));
        System.out.println("naturalOrdering:" + naturalOrdering.sortedCopy(list));
        System.out.println("leastOf list:" + naturalOrdering.leastOf(list, 3));
        System.out.println("greatestOf:" + naturalOrdering.greatestOf(list, 3));
        System.out.println("reverse list :" + naturalOrdering.reverse().sortedCopy(list));
        System.out.println("isOrdered list :" + naturalOrdering.isOrdered(list));
        System.out.println("isOrdered list :" + naturalOrdering.reverse().isOrdered(list));
        list.add(null);
        System.out.println(" add null list:" + list);
        System.out.println("nullsFirst list :" + naturalOrdering.nullsFirst().sortedCopy(list));
        System.out.println("nullsLast list :" + naturalOrdering.nullsLast().sortedCopy(list));

//     　　onResultOf(Function)：将function应用在各个元素上之后, 在使用原始ordering进行排序；
//        考虑到排序器应该能处理sortedBy为null的情况，我们可以使用下面的链式调用来合成排序器：
        Foo foo1 = new Foo("a", 1);
        Foo foo2 = new Foo("b", 0);
        Foo foo3 = new Foo("c", 2);
        Foo foo4 = new Foo("a", 0);


        List<Foo> fooList = ImmutableList.of(foo1, foo2, foo3, foo4);
        Ordering<Foo> ordering = Ordering.natural().nullsFirst().onResultOf(new Function<Foo, String>() {
            public String apply(Foo foo) {
                return foo.sortedBy;
            }
        });
        System.out.println(ordering.sortedCopy(fooList));
//        当阅读链式调用产生的排序器时，应该从后往前读。上面的例子中，排序器首先调用apply方法获取sortedBy值，
// 并把sortedBy为null的元素都放到最前面，然后把剩下的元素按sortedBy进行自然排序。之所以要从后往前读，是因为每次链式调用都是用后面的方法包装了前面的排序器。
//        注：用compound方法包装排序器时，就不应遵循从后往前读的原则。为了避免理解上的混乱，
// 请不要把compound写在一长串链式调用的中间，你可以另起一行，在链中最先或最后调用compound。
        //        compound(Comparator)：返回一个使用Comparator的Ordering，Comparator作为第二排序元素，例如对bug列表进行排序，先根据bug的级别，再根据优先级进行排序；
        Ordering<Foo> testOrdering = ordering.compound(new Comparator<Foo>() {
            @Override
            public int compare(Foo o1, Foo o2) {
                return Ints.compare(o1.notSortedBy, o2.notSortedBy);
            }
        });
        System.out.println(testOrdering.sortedCopy(fooList));
        //     　　lexicographical()：返回一个按照字典元素迭代的Ordering；

    }

    @Test
    public void intOrderIng() {
        List intList = Lists.newArrayList();
        for (int i = 1; i < 20; i++) {
            intList.add(new Random().nextInt(i * 200));
        }
        System.out.println("origin int list =" + intList);

        Ordering<Integer> intOrdering = new Ordering<Integer>() {
            @Override
            public int compare(Integer left, Integer right) {
                return left.compareTo(right);//排序完成后,默认为从小到大.
            }
        };

        List greateThan300 = intOrdering.greatestOf(intList, 300);
        System.out.println(greateThan300);
        System.out.println(intOrdering.isOrdered(greateThan300));//是否是排好顺序的.

        List orderIntList = intOrdering.sortedCopy(greateThan300);
        System.out.println("orderedIntList=" + orderIntList);

        Ordering lexicographical = intOrdering.lexicographical();


        List list = Lists.newArrayList();
        intList.add(1);
        list.add(intOrdering.sortedCopy(intList));
        list.add(orderIntList);
        System.out.println("intList=" + intOrdering.sortedCopy(intList));
        System.out.println("orderIntList=" + orderIntList);
        //先按list排序，再按list内部排序
        List<Iterable<Integer>> iterables = lexicographical.sortedCopy(list);//不知道这个类有啥用,先有个印象吧,这个东西还是挺吊的.
        for (Iterable<Integer> iterable : iterables) {
            for (Integer integer : iterable) {
                System.out.println(integer);
            }
        }

    }

}

class Foo {
    @Nullable
    String sortedBy;
    int notSortedBy;

    public Foo(String sortedBy, int notSortedBy) {
        this.sortedBy = sortedBy;
        this.notSortedBy = notSortedBy;
    }

    @Override
    public String toString() {
        return ReflectionToStringBuilder.toString(this, ToStringStyle.SHORT_PREFIX_STYLE);
    }
}